const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');

class UnusedCodePlugin {
  constructor(options = {}) {
    // 插件默认配置项与用户配置合并
    this.options = {
      // 指定要处理的文件类型
      extensions: ['.js', '.jsx', '.ts', '.tsx'],
      // 是否删除所有的console.*语句
      removeConsole: true,
      // 是否删除未被引用的import语句
      removeUnusedImports: true,
      // 是否删除永远不会执行的代码块
      removeDeadCode: true,
      ...options
    };
  }

  apply(compiler) {
    // 注册webpack编译钩子
    compiler.hooks.compilation.tap('UnusedCodePlugin', (compilation) => {
      // 在模块优化阶段处理
      compilation.hooks.optimizeChunkModules.tap('UnusedCodePlugin', (chunks, modules) => {
        // 获取 ModuleGraph 实例
        const moduleGraph = compilation.moduleGraph;

        modules.forEach(module => {
          // 检查是否需要处理该模块
          if (this.shouldProcessModule(module)) {
            try {
              // 获取模块源码
              const source = module._source._value;
              // 使用新的 API 获取已使用的导出
              const usedExports = Array.from(moduleGraph.getUsedExports(module) || []);
              // 转换代码并移除无用代码
              const transformedCode = this.transformCode(source, usedExports);
              // 更新模块源码
              module._source._value = transformedCode;
            } catch (error) {
              // 将错误添加到webpack警告中
              compilation.warnings.push(
                new Error(`UnusedCodePlugin: Error processing ${module.resource}: ${error.message}`)
              );
            }
          }
        });
      });
    });
  }

  // 检查模块是否需要处理
  shouldProcessModule(module) {
    return module.resource && 
           this.options.extensions.some(ext => module.resource.endsWith(ext));
  }

  // 代码转换的核心方法
  transformCode(source, usedExports) {
    try {
      console.log('开始转换代码，使用的导出:', usedExports);
      
      const ast = parser.parse(source, {
        sourceType: 'module',
        plugins: ['jsx', 'typescript', 'classProperties', 'decorators-legacy']
      });

      const nodesToRemove = new Set();

      traverse(ast, {
        // 处理import语句
        ImportDeclaration: (path) => {
          if (this.options.removeUnusedImports) {
            const specifiers = path.node.specifiers;
            // 过滤出被使用的导入
            const usedSpecifiers = specifiers.filter(specifier => {
              const name = specifier.local.name;
              return usedExports.includes(name);
            });

            // 如果没有使用的导入，删除整个import语句
            if (usedSpecifiers.length === 0) {
              nodesToRemove.add(path);
            } 
            // 如果部分使用，只保留使用的部分
            else if (usedSpecifiers.length !== specifiers.length) {
              path.node.specifiers = usedSpecifiers;
            }
          }
        },

        // 处理console语句
        CallExpression: (path) => {
          if (this.options.removeConsole) {
            const callee = path.node.callee;
            // 检查是否是console调用
            if (
              t.isMemberExpression(callee) &&
              t.isIdentifier(callee.object, { name: 'console' })
            ) {
              nodesToRemove.add(path);
            }
          }
        },

        // 处理条件语句中的死代码
        IfStatement: (path) => {
          if (this.options.removeDeadCode) {
            const test = path.node.test;
            if (t.isBooleanLiteral(test)) {
              // 如果条件永远为false，删除整个if语句
              if (test.value === false) {
                nodesToRemove.add(path);
              } 
              // 如果条件永远为true，直接使用if块中的代码
              else if (test.value === true) {
                path.replaceWithMultiple(path.node.consequent.body);
              }
            }
          }
        },

        // 处理未使用的函数声明
        FunctionDeclaration: (path) => {
          const name = path.node.id.name;
          // 如果函数名不在已使用的导出中，删除该函数
          if (!usedExports.includes(name)) {
            nodesToRemove.add(path);
          }
        },

        // 处理变量声明
        VariableDeclaration: (path) => {
          const declarations = path.node.declarations;
          // 过滤出被使用的变量声明
          const usedDeclarations = declarations.filter(declaration => {
            if (t.isIdentifier(declaration.id)) {
              return usedExports.includes(declaration.id.name);
            }
            return true; // 对于解构等复杂声明，暂时保留
          });

          // 根据使用情况决定是否删除或部分保留
          if (usedDeclarations.length === 0) {
            nodesToRemove.add(path);
          } else if (usedDeclarations.length !== declarations.length) {
            path.node.declarations = usedDeclarations;
          }
        }
      });

      nodesToRemove.forEach(path => {
        path.remove();
      });

      // 修改生成配置
      const output = generate(ast, {
        retainLines: true,
        compact: false,
        sourceMaps: true,
        decoratorsBeforeExport: true,
        jsescOption: {
          minimal: true
        }
      });

      console.log('代码转换完成');
      return output.code;
    } catch (error) {
      console.error('代码转换错误:', error);
      // 如果转换失败，返回原始代码
      return source;
    }
  }
}

module.exports = UnusedCodePlugin; 